home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 34 / Amiga Format CD34 (1998-11-20)(Future Publishing)(GB)[!][Christmas issue].iso / -seriously_amiga- / programming / c / mesa-2.6 / src / vbrender.c < prev   
C/C++ Source or Header  |  1998-10-01  |  39KB  |  1,259 lines

  1. /* $Id: vbrender.c,v 1.21 1998/01/18 15:04:48 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  2.6
  6.  * Copyright (C) 1995-1997  Brian Paul
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * vbrender.c
  26.  *
  27.  * Modified  27 Jun 1998
  28.  * by Jarno van der Linden
  29.  * jarno@kcbbs.gen.nz
  30.  *
  31.  * Based on vbrender.c ver 1.21
  32.  * Some minor changes to work around SAS/C 6.59 optimizer bug
  33.  *
  34.  */
  35.  
  36.  
  37. /*
  38.  * Render points, lines, and polygons.  The only entry point to this
  39.  * file is the gl_render_vb() function.  This function is called after
  40.  * the vertex buffer has filled up or glEnd() has been called.
  41.  *
  42.  * This file basically only makes calls to the clipping functions and
  43.  * the point, line and triangle rasterizers via the function pointers.
  44.  *    context->Driver.PointsFunc()
  45.  *    context->Driver.LineFunc()
  46.  *    context->Driver.TriangleFunc()
  47.  */
  48.  
  49.  
  50. #ifdef PC_HEADER
  51. #include "all.h"
  52. #else
  53. #include "clip.h"
  54. #include "context.h"
  55. #include "light.h"
  56. #include "macros.h"
  57. #include "matrix.h"
  58. #include "pb.h"
  59. #include "types.h"
  60. #include "vb.h"
  61. #include "vbrender.h"
  62. #include "xform.h"
  63. #endif
  64.  
  65.  
  66. /*
  67.  * This file implements rendering of points, lines and polygons defined by
  68.  * vertices in the vertex buffer.
  69.  */
  70.  
  71.  
  72.  
  73. #ifdef PROFILE
  74. #  define START_PROFILE                \
  75.     {                    \
  76.        GLdouble t0 = gl_time();
  77.  
  78. #  define END_PROFILE( TIMER, COUNTER, INCR )    \
  79.        TIMER += (gl_time() - t0);        \
  80.        COUNTER += INCR;            \
  81.     }
  82. #else
  83. #  define START_PROFILE
  84. #  define END_PROFILE( TIMER, COUNTER, INCR )
  85. #endif
  86.  
  87.  
  88.  
  89.  
  90. /*
  91.  * Render a line segment from VB[v1] to VB[v2] when either one or both
  92.  * endpoints must be clipped.
  93.  */
  94. static void render_clipped_line( GLcontext *ctx, GLuint v1, GLuint v2 )
  95. {
  96.    GLfloat ndc_x, ndc_y, ndc_z;
  97.    GLuint provoking_vertex;
  98.    struct vertex_buffer *VB = ctx->VB;
  99.  
  100.    /* which vertex dictates the color when flat shading: */
  101.    provoking_vertex = v2;
  102.  
  103.    /*
  104.     * Clipping may introduce new vertices.  New vertices will be stored
  105.     * in the vertex buffer arrays starting with location VB->Free.  After
  106.     * we've rendered the line, these extra vertices can be overwritten.
  107.     */
  108.    VB->Free = VB_MAX;
  109.  
  110.    /* Clip against user clipping planes */
  111.    if (ctx->Transform.AnyClip) {
  112.       GLuint orig_v1 = v1, orig_v2 = v2;
  113.       if (gl_userclip_line( ctx, &v1, &v2 )==0)
  114.     return;
  115.       /* Apply projection matrix:  clip = Proj * eye */
  116.       if (v1!=orig_v1) {
  117.          TRANSFORM_POINT( VB->Clip[v1], ctx->ProjectionMatrix, VB->Eye[v1] );
  118.       }
  119.       if (v2!=orig_v2) {
  120.          TRANSFORM_POINT( VB->Clip[v2], ctx->ProjectionMatrix, VB->Eye[v2] );
  121.       }
  122.    }
  123.  
  124.    /* Clip against view volume */
  125.    if (gl_viewclip_line( ctx, &v1, &v2 )==0)
  126.       return;
  127.  
  128.    /* Transform from clip coords to ndc:  ndc = clip / W */
  129.    if (VB->Clip[v1][3] != 0.0F) {
  130.       GLfloat wInv = 1.0F / VB->Clip[v1][3];
  131.       ndc_x = VB->Clip[v1][0] * wInv;
  132.       ndc_y = VB->Clip[v1][1] * wInv;
  133.       ndc_z = VB->Clip[v1][2] * wInv;
  134.    }
  135.    else {
  136.       /* Can't divide by zero, so... */
  137.       ndc_x = ndc_y = ndc_z = 0.0F;
  138.    }
  139.  
  140.    /* Map ndc coord to window coords. */
  141.    VB->Win[v1][0] = ndc_x * ctx->Viewport.Sx + ctx->Viewport.Tx;
  142.    VB->Win[v1][1] = ndc_y * ctx->Viewport.Sy + ctx->Viewport.Ty;
  143.    VB->Win[v1][2] = ndc_z * ctx->Viewport.Sz + ctx->Viewport.Tz;
  144.  
  145.    /* Transform from clip coords to ndc:  ndc = clip / W */
  146.    if (VB->Clip[v2][3] != 0.0F) {
  147.       GLfloat wInv = 1.0F / VB->Clip[v2][3];
  148.       ndc_x = VB->Clip[v2][0] * wInv;
  149.       ndc_y = VB->Clip[v2][1] * wInv;
  150.       ndc_z = VB->Clip[v2][2] * wInv;
  151.    }
  152.    else {
  153.       /* Can't divide by zero, so... */
  154.       ndc_x = ndc_y = ndc_z = 0.0F;
  155.    }
  156.  
  157.    /* Map ndc coord to window coords. */
  158.    VB->Win[v2][0] = ndc_x * ctx->Viewport.Sx + ctx->Viewport.Tx;
  159.    VB->Win[v2][1] = ndc_y * ctx->Viewport.Sy + ctx->Viewport.Ty;
  160.    VB->Win[v2][2] = ndc_z * ctx->Viewport.Sz + ctx->Viewport.Tz;
  161.  
  162.    if (ctx->Driver.RasterSetup) {
  163.       /* Device driver rasterization setup */
  164.       (*ctx->Driver.RasterSetup)( ctx, v1, v1+1 );
  165.       (*ctx->Driver.RasterSetup)( ctx, v2, v2+1 );
  166.    }
  167.  
  168.    START_PROFILE
  169.    (*ctx->Driver.LineFunc)( ctx, v1, v2, provoking_vertex );
  170.    END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
  171. }
  172.  
  173.  
  174.  
  175. /*
  176.  * Compute Z offsets for a polygon with plane defined by (A,B,C,D)
  177.  * D is not needed.
  178.  */
  179. static void offset_polygon( GLcontext *ctx, GLfloat a, GLfloat b, GLfloat c )
  180. {
  181.    GLfloat ac, bc, m;
  182.    GLfloat offset;
  183.  
  184.    if (c<0.001F && c>-0.001F) {
  185.       /* to prevent underflow problems */
  186.       offset = 0.0F;
  187.    }
  188.    else {
  189.       ac = a / c;
  190.       bc = b / c;
  191.       if (ac<0.0F)  ac = -ac;
  192.       if (bc<0.0F)  bc = -bc;
  193.       m = MAX2( ac, bc );
  194.       /* m = sqrt( ac*ac + bc*bc ); */
  195.  
  196.       offset = m * ctx->Polygon.OffsetFactor + ctx->Polygon.OffsetUnits;
  197.    }
  198.  
  199.    ctx->PointZoffset   = ctx->Polygon.OffsetPoint ? offset : 0.0F;
  200.    ctx->LineZoffset    = ctx->Polygon.OffsetLine  ? offset : 0.0F;
  201.    ctx->PolygonZoffset = ctx->Polygon.OffsetFill  ? offset : 0.0F;
  202. }
  203.  
  204.  
  205.  
  206. /*
  207.  * When glPolygonMode() is used to specify that the front/back rendering
  208.  * mode for polygons is not GL_FILL we end up calling this function.
  209.  */
  210. static void unfilled_polygon( GLcontext *ctx,
  211.                               GLuint n, GLuint vlist[],
  212.                               GLuint pv, GLuint facing )
  213. {
  214.    GLenum mode = facing ? ctx->Polygon.BackMode : ctx->Polygon.FrontMode;
  215.    struct vertex_buffer *VB = ctx->VB;
  216.  
  217.    if (mode==GL_POINT) {
  218.       GLint i, j;
  219.       GLboolean edge;
  220.  
  221.       if (   ctx->Primitive==GL_TRIANGLES
  222.           || ctx->Primitive==GL_QUADS
  223.           || ctx->Primitive==GL_POLYGON) {
  224.          edge = GL_FALSE;
  225.       }
  226.       else {
  227.          edge = GL_TRUE;
  228.       }
  229.  
  230.       for (i=0;i<n;i++) {
  231.          j = vlist[i];
  232.          if (edge || VB->Edgeflag[j]) {
  233.             (*ctx->Driver.PointsFunc)( ctx, j, j );
  234.          }
  235.       }
  236.    }
  237.    else if (mode==GL_LINE) {
  238.       GLuint i, j0, j1;
  239.       GLboolean edge;
  240.  
  241.       ctx->StippleCounter = 0;
  242.  
  243.       if (   ctx->Primitive==GL_TRIANGLES
  244.           || ctx->Primitive==GL_QUADS
  245.           || ctx->Primitive==GL_POLYGON) {
  246.          edge = GL_FALSE;
  247.       }
  248.       else {
  249.          edge = GL_TRUE;
  250.       }
  251.  
  252.       /* draw the edges */
  253.       for (i=0;i<n;i++) {
  254.          j0 = (i==0) ? vlist[n-1] : vlist[i-1];
  255.          j1 = vlist[i];
  256.          if (edge || VB->Edgeflag[j0]) {
  257.             START_PROFILE
  258.             (*ctx->Driver.LineFunc)( ctx, j0, j1, pv );
  259.             END_PROFILE( ctx->LineTime, ctx->LineCount, 1 )
  260.          }
  261.       }
  262.    }
  263.    else {
  264.       /* Fill the polygon */
  265.       GLuint j0, i, j;
  266.       j0 = vlist[0];
  267.       for (i=2;i<n;i++) {
  268.          j = i-1;
  269.          START_PROFILE
  270.          (*ctx->Driver.TriangleFunc)( ctx, j0, vlist[j], vlist[j+1], pv );
  271.          END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 )
  272.       }
  273.    }
  274. }
  275.  
  276.  
  277. /*
  278.  * Compute signed area of the n-sided polgyon specified by vertices vb->Win[]
  279.  * and vertex list vlist[].
  280.  * A clockwise polygon will return a negative area.
  281.  * A counter-clockwise polygon will return a positive area.
  282.  */
  283. static GLfloat polygon_area( const struct vertex_buffer *vb,
  284.                              GLuint n, const GLuint vlist[] )
  285. {
  286.    GLfloat area = 0.0F;
  287.    GLint i;
  288.    for (i=0;i<n;i++) {
  289.       /* area = sum of trapezoids */
  290.       GLuint j0 = vlist[i];
  291.       GLuint j1 = vlist[(i+1)%n];
  292.       GLfloat x0 = vb->Win[j0][0];
  293.       GLfloat y0 = vb->Win[j0][1];
  294.       GLfloat x1 = vb->Win[j1][0];
  295.       GLfloat y1 = vb->Win[j1][1];
  296.       GLfloat trapArea = (x0-x1)*(y0+y1);  /* Note: no divide by two here! */
  297.       area += trapArea;
  298.    }
  299.    re